import Core from "../Core";
import { randomInt } from "../utils/RandomUtils";
import { Singleton } from "../utils/Singleton";
import { getCache, setCache } from "../utils/StorageUtils";
import { getNowMillisecond } from "../utils/TimeUtils";

export default class AudioManager extends Singleton<AudioManager> {
  public vibrate: number = 1;
  public musicVolume: number = 1;
  public soundVolume: number = 1;
  private playingSFX = new Map<string, number>(); // url -> audioId
  bgmAudioID: number = -1;
  audioId: number = -1;
  musicIndex = randomInt(0, 4);

  private constructor() {
    super();
  }
  loadSounds() {
    var musicVolume: any = getCache("musicVolume");
    var soundVolume: any = getCache("soundVolume");
    var vibrate: any = getCache("vibrate");
    this.musicVolume = musicVolume == null ? 1 : Number(musicVolume);
    this.soundVolume = soundVolume == null ? 1 : Number(soundVolume);
    this.vibrate = vibrate == null ? 1 : Number(vibrate);
    this.playBGM("bgm2");
  }

  private bgm_url: string = "bgm2";
  async playBGM(url: string) {
    this.bgm_url = url;
    if (this.bgmAudioID == 0) {
      cc.audioEngine.stop(this.bgmAudioID);
      return;
    }
    let audio = await Core.resHelper.load<cc.AudioClip>(
      url,
      cc.AudioClip,
      "sounds"
    );
    if (audio) {
      if (this.bgmAudioID >= 0) {
        cc.audioEngine.stop(this.bgmAudioID);
      }
      if (this.musicVolume > 0) {
        this.bgmAudioID = cc.audioEngine.play(audio, true, this.musicVolume);
      }
    }
  }

  stopSFX(audioId: any) {
    var ok = cc.audioEngine.stop(audioId);
    return ok;
  }

  playButtonClicked() {
    this.playSFX("ui_button_click");
  }

  private lastplaysfxtime = {};
  async playSFX(
    url: string,
    delaySeconds: number = 0,
    checktime: boolean = true
  ): Promise<number> {
    // 返回 audioId
    if (this.soundVolume == 0) {
      return -1;
    }

    if (delaySeconds > 0) {
      setTimeout(() => {
        this.playSFX(url);
      }, delaySeconds * 1000);
      return -1;
    }

    if (checktime && this.lastplaysfxtime[url]) {
      if (getNowMillisecond() - this.lastplaysfxtime[url] < 300) {
        return -1;
      }
    }

    this.lastplaysfxtime[url] = getNowMillisecond();
    let audio = await Core.resHelper.load<cc.AudioClip>(
      url,
      cc.AudioClip,
      "sounds"
    );

    if (audio && this.soundVolume > 0) {
      const audioId = cc.audioEngine.play(audio, false, this.soundVolume);

      this.playingSFX.set(url, audioId);

      // 音效结束后自动清理
      cc.audioEngine.setFinishCallback(audioId, () => {
        this.playingSFX.delete(url);
      });
      return audioId;
    }

    return -1;
  }

  // 新增：停止某个音效（通过 URL）
  stopSFXByUrl(url: string) {
    if (this.playingSFX.has(url)) {
      const audioId = this.playingSFX.get(url)!;
      cc.audioEngine.stop(audioId);
      this.playingSFX.delete(url);
    }
  }

  pauseBGM() {
    if (this.bgmAudioID >= 0) {
      cc.audioEngine.pause(this.bgmAudioID);
    }
  }

  resumBGM() {
    if (this.bgmAudioID >= 0) {
      cc.audioEngine.resume(this.bgmAudioID);
    }
  }

  setMusicVolume(v: number, force: boolean = false) {
    if (this.musicVolume != v || force) {
      setCache("musicVolume", v + "");
      this.musicVolume = v;
      cc.audioEngine.setVolume(this.bgmAudioID, v);
    }
    // MsgHints.show(this.bgmAudioID + "_" + v)
    if (this.bgmAudioID >= 0) {
      if (v > 0) {
        cc.audioEngine.resume(this.bgmAudioID);
      } else {
        cc.audioEngine.pause(this.bgmAudioID);
      }
    } else {
      this.playBGM(this.bgm_url);
    }
  }

  setSoundVolume(v: number, force: boolean = false) {
    if (this.soundVolume != v || force) {
      setCache("soundVolume", v + "");
      this.soundVolume = v;
    }
  }

  vibrateShort(delaySeconds: number = 0) {
    if (delaySeconds > 0) {
      setTimeout(() => {
        this.vibrateShort();
      }, delaySeconds * 1000);
      return;
    }
    let wx = window["wx"];
    if (wx && this.vibrate) wx.vibrateShort();
  }

  vibrateLong() {
    let wx = window["wx"];
    if (wx && this.vibrate) wx.vibrateLong();
  }
}
